package com.wh.concurrent.atomic;

public class Test {
	
	public static void main(String[] args) {
		final P1 p1 = new P1();
		Thread t1 = new Thread() {
			@Override
			public void run() {
				while(true) {
					p1.set1();
				}
			}
		};
		t1.start();
		
		Thread t2 = new Thread() {
			@Override
			public void run() {
				while(true) {
					p1.set2();
				}
			}
		};
		t2.start();
		
		Thread t3 = new Thread() {
			@Override
			public void run() {
				while(true) {
					p1.check();
				}
			}
		};
		t3.start();
		
	}
}


/*陷阱一：并发执行
并发执行就是多个操作一起执行，CPU 执行不同上下文（可理解为不同线程）发过来的指令。操作系统上层看上去就像是并行处理一样。



也就是说，在编程语言层面，一个简单的操作同样需要考虑并发问题。

 

小 K 首先是栽在了 check() 中的 if 判断上和设值是存在并发的，不能保证 0 != b 这个判断真（此时 b 为 -1）后恰好 b 被赋值为 0 时判断 1 != b。

 

除此外，无论 JVM、操作系统、CPU 层面对指令如何优化、重排，最终都是逐一执行单一指令，唯一不同的就是不同层面可能会对执行加以限制，

比如加入原子操作，最终保证 CPU 能够完整执行一组指令。

陷阱二：JVM 赋值操作

一些赋值操作不是原子性的。“纳尼？”



Java 基础类型中，long 和 double 是 64 位长的。32 位架构 CPU 的算术逻辑单元（ALU）宽度是 32 位的，在处理大于 32 位操作时需要处理两次。

 

“这不是<计算机组成原理与汇编>么”，小 K 顿时感到大学白上了，不懂学以致用 T_T~

 

题目执行打印 4294967295、-4294967296 就是因为读时高 32 位或低 32 位被其他写覆盖了（看一下这两个数字的二进制就知道了）。

 

Java 已经是封装底层细节很好的语言了，但依然需要注意这些陷阱，可以使用并发处理包 java.util.concurrent.atomic 中包含了一系列无锁原子操作类型，

也可以使用 volatile 关键字保证线程间变量的可见性。

 

其实这道题目只要解决了并发问题，也就保证了每个执行单元（set1()、set2()、check()）中赋值、比较的正确性。可以把同步方法执行看作序列化的事务，各中操作不会相互影响。*/
